package isnork.g2.utility;

import isnork.sim.GameObject.Direction;

import java.awt.geom.Point2D;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class Utility {
	
	 public static final Direction[] DIRECTIONS = {Direction.E, Direction.NE,
	        Direction.N, Direction.NW, Direction.W, Direction.SW, Direction.S, Direction.SE};
	
	public static Direction RelativeDirection(Point2D x, Point2D y) {
		// if x and y are the same location
		if (x.distance(y) < 0.5)
			return Direction.STAYPUT;
		Point2D vec = new Point2D.Double(y.getX() - x.getX(), x.getY()
				- y.getY());
		double degree = Math.atan2(vec.getY(), vec.getX());
		degree = degree / Math.PI * 180;
		double slice = 22.5;
		if (degree < -slice * 7)
			return Direction.W;
		if (degree < -slice * 5)
			return Direction.SW;
		if (degree < -slice * 3)
			return Direction.S;
		if (degree < -slice)
			return Direction.SE;
		if (degree < slice)
			return Direction.E;
		if (degree < slice * 3)
			return Direction.NE;
		if (degree < slice * 5)
			return Direction.N;
		if (degree < slice * 7)
			return Direction.NW;
		return Direction.W;
	}

	public static Direction directionTowardCreature(Point2D diver,
			Point2D creature) {
		int quadrent = 1;
		if (creature.getY() - diver.getY() > 0) {
			quadrent = 0;
		}

		if (creature.getX() - diver.getX() > 0) {
			quadrent = quadrent == 0 ? 4 : 1;
		} else {
			quadrent = quadrent == 0 ? 3 : 2;
		}

		double radians = Math.atan(Math.abs(creature.getY() - diver.getY())
				/ Math.abs(creature.getX() - diver.getX()));

		double degrees = Math.toDegrees(radians);
		
		if(quadrent == 2 || quadrent == 4) {
			degrees = 90 - degrees;
		}
		
		int quad = 2 * (quadrent - 1);
		
		if (degrees > 22.5)
			quad++;
		if (degrees > 45 + 22.5)
			quad++;
		
		quad = quad % 8;
		
		return quad < 0 ? null : DIRECTIONS[quad];
	}
	
	public static void Add(Map<Direction, Double> a, Map<Direction, Double> b) {
		for (Entry<Direction, Double> e : b.entrySet()) {
			double utility = a.get(e.getKey());
			a.put(e.getKey(), utility + e.getValue());
		}
	}

	public static List<Direction> AdjacentDirections(Direction dir) {
		return adjacent.get(dir);
	}

	private static Map<Direction, List<Direction>> adjacent;
	static {
		adjacent = new HashMap<Direction, List<Direction> >();
		List<Direction> l;
		// E: SE, NE
		l = new LinkedList<Direction>();
		l.add(Direction.SE);
		l.add(Direction.NE);
		adjacent.put(Direction.E, l);
		
		// N: NE, NW
		l = new LinkedList<Direction>();
		l.add(Direction.NE);
		l.add(Direction.NW);
		adjacent.put(Direction.N, l);
		
		// NE: N, E
		l = new LinkedList<Direction>();
		l.add(Direction.N);
		l.add(Direction.E);
		adjacent.put(Direction.NE, l);
		
		// NW: N, W
		l = new LinkedList<Direction>();
		l.add(Direction.N);
		l.add(Direction.W);
		adjacent.put(Direction.NW, l);
		
		// S: SW, SE
		l = new LinkedList<Direction>();
		l.add(Direction.SW);
		l.add(Direction.SE);
		adjacent.put(Direction.S, l);
		
		// SE: S, E
		l = new LinkedList<Direction>();
		l.add(Direction.S);
		l.add(Direction.E);
		adjacent.put(Direction.SE, l);
		
		// SW: S, W
		l = new LinkedList<Direction>();
		l.add(Direction.S);
		l.add(Direction.W);
		adjacent.put(Direction.SW, l);
		
		// W: SW, NW
		l = new LinkedList<Direction>();
		l.add(Direction.SW);
		l.add(Direction.NW);
		adjacent.put(Direction.W, l);
		
		// stay: all
		l = new LinkedList<Direction>();
		l = Direction.allBut(Direction.STAYPUT);
		adjacent.put(Direction.STAYPUT, l);
	}
}
